import * as THREE from "three";

// 引入轨道控制器控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

console.log(THREE);

//three.js 基本内容

// 1.创建场景  场景能够让你在什么地方、摆放什么东西来交给three.js来渲染，这是你放置物体、灯光和摄像机的地方。
const scene = new THREE.Scene();

// 2.创建相机 

//  透视相机（PerspectiveCamera）这一摄像机使用perspective projection（透视投影）来进行投影。
// 这一投影模式被用来模拟人眼所看到的景象，它是3D场景的渲染中使用得最普遍的投影模式。
// PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
// fov — 摄像机视锥体垂直视野角度   // aspect — 摄像机视锥体长宽比  // near — 摄像机视锥体近端面  // far — 摄像机视锥体远端面
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

//2.1设置相机的位置 position表示对象局部位置的Vector3。默认值为(0, 0, 0)。

// Vector3( x : Float, y : Float, z : Float )   该类表示的是一个三维向量（3D vector）。'
//  一个三维向量表示的是一个有顺序的、三个为一组的数字组合（标记为x、y和z）， 可被用来表示很多事物:
//  一个位于三维空间中的点。
// 一个在三维空间中的方向与长度的定义。在three.js中，长度总是从(0, 0, 0)到(x, y, z)的 Euclidean distance（欧几里德距离，即直线距离）， 
// 方向也是从(0, 0, 0)到(x, y, z)的方向。
// .set ( x : Float, y : Float, z : Float ) : this
// 设置该向量的x、y 和 z 分量。


camera.position.set(0, 0, 10);
scene.add(camera); //添加相机到场景中

// 3.创建物体
// 3.1创建几何体
// BoxGeometry 是四边形的原始几何类，它通常使用构造函数所提供的 “width”、“height”、“depth” 参数来创建立方体或者不规则四边形。
// BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
// width — X 轴上面的宽度，默认值为 1。 height — Y 轴上面的高度，默认值为 1。 depth — Z 轴上面的深度，默认值为 1。
// widthSegments — （可选）宽度的分段数，默认值是 1heightSegments — （可选）高度的分段数，默认值是 1。 depthSegments — （可选）深度的分段数，默认值是 1。
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
// 3.2创建物体材质 
// 基础网格材质(MeshBasicMaterial) 一个以简单着色（平面或线框）方式来绘制几何体的材质。 这种材质不受光照的影响。
// MeshBasicMaterial( parameters : Object )
// parameters - (可选)用于定义材质外观的对象，具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
// 材质(Material)材质的抽象基类。
// 材质描述了对象objects的外观。它们的定义方式与渲染器无关， 因此，如果您决定使用不同的渲染器，不必重写材质。
// 所有其他材质类型都继承了以下属性和方法（尽管它们可能具有不同的默认值）。
// 属性color例外，其可以作为十六进制字符串传递，默认情况下为 0xffffff（白色），内部调用Color.set(color)。
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });

// 3.3根据几何体与材质创建物体
// 网格（Mesh） 表示基于以三角形为polygon mesh（多边形网格）的物体的类。 同时也作为其他类的基类，例如SkinnedMesh。
// // Mesh( geometry : BufferGeometry, material : Material )
// geometry —— （可选）BufferGeometry的实例，默认值是一个新的BufferGeometry。
// material —— （可选）一个Material，或是一个包含有Material的数组，默认是一个新的MeshBasicMaterial。
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube); //将物体添加到场景中

// 4.渲染
// 初始化渲染器
// WebGLRenderer WebGL Render 用WebGL渲染出你精心制作的场景。
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// .domElement : DOMElement   一个canvas，渲染器在其上绘制输出。
// 渲染器的构造函数会自动创建(如果没有传入canvas参数);你需要做的仅仅是像下面这样将它加页面里去:
document.body.appendChild(renderer.domElement); //将绘制canvas添加到页面里

// 使用渲染器，通过相机将场景渲染出来
// .render ( scene : Object3D, camera : Camera ) : undefined
// 用相机(camera)渲染一个场景(scene)或是其它类型的object。
// 渲染一般是在canvas上完成的，或者是renderTarget(如果有指定)
// 如果forceClear值是true，那么颜色、深度及模板缓存将会在渲染之前清除，即使渲染器的autoClear属性值是false
// 即便forceClear设为true, 也可以通过将autoClearColor、autoClearStencil或autoClearDepth属性的值设为false来阻止对应缓存被清除。
// renderer.render(scene,camera);


//创建轨道控制器
// OrbitControls( object : Camera, domElement : HTMLDOMElement )
// object: （必须）将要被控制的相机。该相机不允许是其他任何对象的子级，除非该对象是场景自身。
// domElement: 用于事件监听的HTML元素。
const controls = new OrbitControls(camera, renderer.domElement);


// 创建坐标轴辅助器
// AxesHelper  用于简单模拟3个坐标轴的对象.
// 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// AxesHelper( size : Number )  size -- (可选的) 表示代表轴的线段长度. 默认为 1.
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 修改位置
// cube.position.set(5,1,0);
cube.position.x = 2;
// 修改物体的局部缩放
// cube.scale.set(3,2,1);
// 物体的局部旋转，以弧度来表示。  Math.PI 3.14 
cube.rotation.set(Math.PI / 4, 0, 0, "YZX");
cube.rotation.x = 80;

// 设置时钟
// Clock该对象用于跟踪时间。如果performance.now可用，则 Clock 对象通过该方法实现，否则回落到使用略欠精准的Date.now来实现。
// .oldTime : Float 存储时钟最后一次调用 start, .getElapsedTime() 或 .getDelta() 方法的时间。默认值是 0。
const clock = new THREE.Clock();


function render() {

    let time = clock.getElapsedTime();
    console.log("时钟运行总时长：" + time);

    // let deltatime = clock.getDelta(); 
    // console.log("两次获取时间的间隔时间" + deltatime); // 0.007  1000/7 = 142  1秒约142帧
    // cube.position.x += 0.01;
    // let t = (time / 1000) % 5;
    let t = time % 5;
    cube.position.x = t * 1;
    // if (cube.position.x > 5) {
    //     cube.position.x = 0;
    // }

    cube.rotation.x += 0.01;

    renderer.render(scene, camera);
    // requestAnimationFrame 是一个用于优化浏览器动画效果的 API。它可以让浏览器在下一次重绘前执行指定的回调函数，
    // 从而可以更加流畅地执行动画效果，避免了使用 setTimeout 或 setInterval 可能引起的性能问题。
    requestAnimationFrame(render);
}

render()







